#ifndef _SAMPLESPACE_H
#define _SAMPLESPACE_H

#include "Sample.h"
#include "Distance.h"

#include <string>
#include <vector>
#include <fstream>
#include <cassert>

using namespace std;

class Cluster;
class Classifier;

class SampleSpace {
public:
    Distance * getDistance() {
        return m_distance;
    }

    Sample * newSample();
    void deleteSample(Sample **sample);

    void newSampleArray(vector<Sample *> &sampleList, int len);
    void deleteSampleArray(vector<Sample *> &sampleList);

    void copy(Sample &dst, const Sample &src) {
        assert(dst.getDimension() == src.getDimension());

        dst.setClass(src.getClass());
        dst.assignFeature(src.getFeature());
    }

    void selfNormalize(vector<Sample *> &sampleList);

    void sampling(vector<Sample *> &sampleList, vector<Sample *> &subset, float factor);

    float distance(const Sample &s1, const Sample &s2) {
        return m_distance->calcDistance(s1, s2);
    }

    /**
     * calculate the distance between s1 and s2, and output the result in out pointer if returned value
     * is true, which means the distance is below threshold.
     *
     * If returned value is false, the value in out pointer is undefined, but we can draw that the distance
     * between s1 and s2 is beyond the threshold.
     */
    bool distance2(const Sample &s1, const Sample &s2, float &out, float threshold) {
        return m_distance->calcDistance2(s1, s2, out, threshold);
    }

    void cluster(Cluster &cluster, vector<Sample *> &sampleList);

    void store2Stream(ofstream &fout);
    static SampleSpace * loadFromStream(ifstream &fin);

    /**
     * File format is as below:
     *     class: feature1 feature2 ... featureN
     * in which pattern is a integer value, and features are all real numbers splited by space.
     *
     * NOTE: "class" label is nessissary, and unkown class's value is specified by user.
     */
    void storeSample2Stream(ofstream &fout, vector<Sample *> &sampleList);
    bool loadSampleFromStream(ifstream &fin, vector<Sample *> &sampleList);

    int getDimension() {
        return m_dim;
    }

    SampleSpace(int dim, Distance::DistanceType distType = Distance::EUCLIDEAN);

    ~SampleSpace(void);

private:
    int m_dim;

    Distance *m_distance;

};

#endif
